package com.zxy.supplier_system.server.service

import com.zxy.supplier_system.server.controller.MarketSettlementPlanResultController
import com.zxy.supplier_system.server.controller.MarketSettlementPlanResultController.PreviewMonthlySettlementResultsResponse
import com.zxy.supplier_system.server.entity.*
import com.zxy.supplier_system.server.repository.MarketSaleDocumentRepository
import com.zxy.supplier_system.server.repository.MarketSettlementPlanRepository
import com.zxy.supplier_system.server.repository.MarketSettlementPlanResultRepository
import com.zxy.supplier_system.server.utils.orElse404
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.math.BigDecimal

@Service
class MarketSettlementPlanResultService(
    private val marketSaleDocumentRepository: MarketSaleDocumentRepository,
    private val systemServiceService: SystemServiceService,
    private val marketSettlementPlanRepository: MarketSettlementPlanRepository,
    private val marketSettlementPlanResultRepository: MarketSettlementPlanResultRepository
) {

    @Transactional(readOnly = true)
    fun previewMonthlyResult(
        marketId: Int,
        year: Int,
        month: Int
    ): PreviewMonthlySettlementResultsResponse {
        val systemService = systemServiceService.getCurrentSystemService()
        val documents =
            this.marketSaleDocumentRepository.findAllByAccount_Market_IdAndAccount_Market_SystemServiceAndYearAndMonth(
                marketId,
                systemService,
                year,
                month
            )
        val allGoodsList = documents.flatMap { document ->
            document.goodsList
        }
        val plan =
            this.marketSettlementPlanRepository.findByMarketIdAndMarket_SystemService(marketId, systemService)
                .orElse404()
        val totalSale = allGoodsList.sumOf { it.totalFee }
        val ruleWithNoteAndSalaryMap = computeRuleNoteWithFeeMap(plan, allGoodsList)

        return PreviewMonthlySettlementResultsResponse(
            ruleWithNoteAndSalaryMap.map { it.value.fee }.sumOf { it },
            totalSale,
            ruleWithNoteAndSalaryMap.map {
                PreviewMonthlySettlementResultsResponse.RuleFee(
                    it.key.id!!,
                    it.key.name,
                    it.value.note,
                    it.value.fee
                )
            }
        )
    }

    private fun computeRuleNoteWithFeeMap(
        plan: MarketSettlementPlan,
        allGoodsList: List<MarketSaleDocumentItem>
    ): Map<MarketSettlementRule, NoteWithFee> {

        val sortedRules = plan.rules.sortByCondition()

        val ruleSaleItemMap =
            // 分类销售记录到不同的结算规则
            MarketSettlementPlanDetailPreviewService.computeRuleSaleItemMap(allGoodsList, sortedRules)
        val ruleTotalSaleMap = ruleSaleItemMap.map { e ->
            val rule = e.key
            val totalSale = e.value.sumOf { it.totalFee }
            rule to totalSale
        }.toMap()
        val ruleWithNoteAndSalaryMap = sortedRules.associateWith {
            var note: String? = null
            val salary = if (it.commissionPercentage == null) {
                it.fixed!!
            } else {
                val decimal = ruleTotalSaleMap[it] ?: BigDecimal.ZERO
                note = "销量${decimal},扣点${it.commissionPercentage}%"
                it.commissionPercentage!! * decimal / BigDecimal(100)
            }
            NoteWithFee(
                note,
                salary,
            )
        }
        return ruleWithNoteAndSalaryMap
    }

    @Transactional(readOnly = true)
    fun getDocuments(
        marketId: Int,
        year: Int,
        month: Int
    ): MarketSettlementPlanResultController.MarketSettlementPlanResultResponse {
        val systemService = systemServiceService.getCurrentSystemService()
        val documents =
            this.marketSaleDocumentRepository.findAllByAccount_Market_IdAndAccount_Market_SystemServiceAndYearAndMonth(
                marketId,
                systemService,
                year,
                month
            )
        val allGoodsList = documents.flatMap { document ->
            document.goodsList
        }

        val totalSale = allGoodsList.sumOf { it.totalFee }
        val settlementPlanResult =
            this.marketSettlementPlanResultRepository.findByMarket_SystemServiceAndMarket_IdAndYearAndMonth(
                systemService,
                marketId,
                year,
                month
            ).orElse404()
        return MarketSettlementPlanResultController.MarketSettlementPlanResultResponse(
            totalSale,
            settlementPlanResult.items.map {
                PreviewMonthlySettlementResultsResponse.RuleFee(
                    it.id!!,
                    it.name,
                    it.note,
                    it.fee
                )
            })
    }

    @Transactional
    fun generateMonthlyResult(marketId: Int, year: Int, month: Int) {
        val systemService = systemServiceService.getCurrentSystemService()
        val documents =
            this.marketSaleDocumentRepository.findAllByAccount_Market_IdAndAccount_Market_SystemServiceAndYearAndMonth(
                marketId,
                systemService,
                year,
                month
            )
        val allGoodsList = documents.flatMap { document ->
            document.goodsList
        }
        val plan =
            this.marketSettlementPlanRepository.findByMarketIdAndMarket_SystemService(marketId, systemService)
                .orElse404()
        val ruleWithNoteAndSalaryMap = computeRuleNoteWithFeeMap(plan, allGoodsList)

        this.marketSettlementPlanResultRepository.save(MarketSettlementPlanResult().apply {
            this.year = year
            this.month = month
            this.items = ruleWithNoteAndSalaryMap.map {
                MarketSettlementDocumentItem().apply {
                    this.fee = it.value.fee
                    this.note = it.value.note
                    this.name = it.key.name
                }
            }.toMutableList()
            this.market = plan.market
            this.rules = plan.rules.map { rule ->
                MarketSettlementPlanResult.MarketSettlementRuleData.fromEntity(rule)
            }
        })

    }

    fun getMonthlyCopiedPlan(
        marketId: Int,
        year: Int,
        month: Int
    ): MarketSettlementPlanResultController.MonthlySettlementPlanResultPlanResponse {
        val plan =
            this.marketSettlementPlanResultRepository.findByMarket_SystemServiceAndMarket_IdAndYearAndMonth(
                systemServiceService.getCurrentSystemService(),
                marketId,
                year,
                month
            ).orElse404()
        return MarketSettlementPlanResultController.MonthlySettlementPlanResultPlanResponse(plan.rules)
    }

    @Transactional(readOnly = true)
    fun findResultSummaries(
        marketId: Int,
        pageable: Pageable
    ): Page<MarketSettlementPlanResultController.MarketSettlementPlanResultSummary> {
        return this.marketSettlementPlanResultRepository.findAllByMarket_SystemServiceAndMarket_Id(
            systemServiceService.getCurrentSystemService(),
            marketId,
            pageable
        ).map { result ->
            MarketSettlementPlanResultController.MarketSettlementPlanResultSummary(
                result.year,
                result.month,
                result.items.map { it.fee }.sumOf { it }
            )
        }
    }


    data class NoteWithFee(val note: String?, val fee: BigDecimal)

}
